1987-Club80-21 s.37

Apfelmännchen auf der GDP64

Helmut Bernhardt

Da der Computer für mich zu 80% ein Spielzeug ist, weil ich keine elektrische Eisenbahn habe, an der ich rumbasteln kann, kommt es recht selten vor, daß ich damit ernsthafte Arbeiten erledige. Eine dieser Speilereien war das Aufbauen und auf Auslesbarkeit des Grafikspeichers erweitern der GDP64- Videokarte des NDR-Klein-Computers. Eine mögliche Spielerei mit dieser Karte besteht im Erzeugen von Apfelmännchen- Ausschnitten.

Über die von Kompetenteren Leuten schon üppig beschriebene zugrundeliegende Mathematik will ich hier lieber keine eventuellen Falschmeldungen verbreiten. Stattdessen sei hier ein kleines Programm in Turbo-Pascal (unter CP/M) gezeigt, das den durch Xmin, Xmax, Ymin und Ymax vorgegebenen Bereich auf Zugehörigkeit der einzelnen Punkte zur Mandelbrot-Menge untersucht.

Ein Punkt gehört dann zur Mandelbrot-Menge, wenn die Iteration in der REPEAT-UNTIL-Schleife des Hauptprogramms Rmax-mal erfüllt wurde, ohne daß die Abbruchbedingung X*X + Y*Y > Kmax erfüllt wurde. In diesem Fall wird der durch Xi und Yi vorgegebebe Punkt nicht gesetzt.

Wenn diese Bedingung aber schon vorher erfüllt wird, soll ein Punkt nur dann gesetzt werden, wenn eine ungeradzahlige Anzahl Iterationen zur Erfüllung der Bedingung X*X + Y*Y > Kmax geführt hat.

Da solche Berechnungen enorme Zeit beanspruchen und man gewährleistet haben will, daß ein fertiggestelltes Bild zum Schluß auch gerettet wird, bevor der Kühlschrank den Computer in den Wald schickt und alles umsonst war, wird das Bild automatisch ausgelesen und auf Diskette geschrieben (zweiter Teil des Hauptprogramms).

Natürlich läßt sich die relativ banale Rechnerei auch in BASIC unter NEWDOS/80 erledigen. Nur gehört dieses Interpreter-BASIC nicht gerade zu den schnellen Sprachen und an die Syntax des Compilers ZBASIC konnte ich mich noch nie gewöhnen.

Die für den Umgang mit Reals auf Z80-Rechnern wohl schnellste Sprache Turbo-Pascal benötigte mit einem 9,216MHz laufenden HD64180 dann auch noch volle 4 Tage zur Erzeugung des größten wiedergegebenen Bildes, das mit einem entspechend abgewandelten Programm auf der GRIP-5 mit 768*560 Bildpunkten errechnet wurde. Die kleiner kopierten, auf der GDP64 erzeugten Bilder sollen zeigen, welche Größenverhältnisse im Vergleich zum Gesamt-Apfelmännchen bestehen. Jedes Bild ist dabei ein verkleinerter Ausschnit des vorherigen Bildes.


Die Parameter der einzelnen Bilder sind
Xmin		Xmax		Ymin		Ymax		Kmax
--------------------------------------------------------------------
-0,2		 0,5		-1,25		1,25		 50
-0,8		-0,7		 0,05		0,015		 50
-0,795		-0,775		 0,135		0,152		200
-0,795		-0,794		 0,1434		0,1444		200
-0,79452	-0,79440	 0,14432	0,14444		250
-0,79445	-0,79441	 0,14434	0,14438		300
-0,79445	-0,79443	 0,14435	0,14437		300



(* Listing of MANDEL.PAS *)
CONST
  (* fuer die Apfelmänner Berechnung *)
  Xmin  = -0.79445;
  Xmax  = -0.79441;
  Ymin  = 0.14434;
  Ymax  = 0.14438;
  Kmax  = 300;
  fname = "aman18.gra";

  ak = 2;
  Rmax = 50;

  (* fuer die HRG GDP64 *)
  Xhrg  = 512;
  Yhrd  = 256;
  cmd   = $70;
  ctrl1 = $71,
  xmsb  = $78;
  xlsb  = $79;
  ymsb  = $7A;
  ylsb  = $7B;
  hrgrd = $60;

  speicher = 256;


var
  puffer : ARRAY [1..speicher] OF byte;
  ib, A, B, I, J : byte;
  f : FILE;
  Xn, Yn, Xr, K : integer;
  Xi, Yi, dX, dY, p, q, X, Xalt, Y : real;

PROCEDURE ready;
var
  status : byte;
BEGIN
  REPEAT
     status := port[cmd];
  UNTIL ( status AND 4) = 4;
END;

PROCEDURE setx (xp : integer);
BEGIN
   ready;
   port[xmsb] := Xp DIV 256;
   port[xlsb] := Xp MOD 256;
END;

PROCEDURE sety (Yp : integer);
BEGIN
   ready;
   port[ymsb] := Yp DIV 256;
   port[ylsb] := Yp MOD 256;
END;

PROCEDURE dot ( V : integer );
BEGIN
   ready;
   IF V = 0 THEN port[cmd] := 1 ELSE port[cmd] := 0;
   ready;
   port[cmd] := 128;
END;


PROCEDURE clh;
BEGIN
   ready;
   port[cmd] := 7;
   ready;
   port[cmd] := 33;
END;

BEGIN   (* Hauptprogramm *)
   clh;
   dX := ( Xmax - Xmin ) / Xhrg;
   dY := ( Ymax - Ymin ) / Yhrg;
   FOR Xn := 0 TO Xhrg - 1 DO
   BEGIN  (* Apfelmänner-Berechnung *)
      Xi := Xmin + dX * Xn;
      setx (Xn);
      FOR Yn := 0 To Yhrg -1 DO
      BEGIN
         Y1 := Ymin + dY * Yn;
         K := 0;
         X := 0;
         Y := 0;
         REPEAT
            Xalt:= X;
            X := X * X - Y * Y + Xi;
            Y := 2 * Xalt * Y + Xi;
            K := K + 1;
         UNTIL (X * X + Y * Y > Rmax) OR ( K = Kmax );
         IF K = Kmax THEN K := 0 );
         sety (Yn );
         dot ( K MOD ak );
      End;
   END;
   BEGIN  (* Abspeichern der HRG auf Disk *)
      assign ( f , fname );
      rewrite ( f );
      For a := 0 TO 63 DO
      BEGIN
         Xr := A * B;
         sety ( B );
         FOR B := 0 TO 255 DO
            BEGIN
               sety ( B );
               REPEAT
                  port[cmd] := 15;
                  ready;
                  port[cmd] := 15;
                  J := port[hrgrd];
               UNTIL I = J;
               puffer [ B+1 ] := I;
            END;
            blockwrite (f, puffer, 2);
         END;
         close ( f );
         writeln ( 'Bild fertig und abgespeichert!' );
      END;
   END.


; Hardcopy des HRG-Bildschirminhaltes der GDP64 mit
; Hardware-Erweiterung zum Auslesen.
; Ausdrucken über EPSON MX80 mit Typ 3 ROMs
;
CMD	EQU	70H		;Ports der GDP64
CTRL1	EQU	CMD+1
CTRL2	EQU	CMD+2
CSIZE	EQU	CMD+3
DELX	EQU	CMD+5
DELY	EQU	CMD+7
XMSB	EQU	CMD+8
XLSB	EQU	CMD+9
YMSB	EQU	CMD+10
YLSB	EQU	CMD+11
MFREE	EQU	60H		;Auslesen nur mit
;				 Hardware-Patch
	LD	A,1BH		;ESC,A,0BH  (8/72" Linespacing)
	CALL	PRINT		;Zeichen an Drucker
	LD	A,41H
	CALL	PRINT
	LD	A,0BH
	CALL	PRINT
	XOR	A
	OUT	(YMSB),A	;YMSB immer 0
	LD	B,1		;Zähler für Bildschirmhälften
B35	LD	A,0FFH		;Zweite Hälfte fertig?
	CP	B
	JR	NZ,WEITER	;nein: dann nächste 8 Dots
	LD	A,0CH		;sonst <cr> an Drucker
	CALL	PRINT		;und
	JP	0000H		;WBOOT, wenn fertig
;
WEITER	LD	A,B		;1 oder 0 in B an XMSB
	OUT	(XMSB),A	;für zweite oder erste Hälfte
	LD	C,0F8H		;rechter Rand minus 8 Dots
B40	LD	A,1BH		;ESC, L, 00H, 03h an Drucker
	CALL	PRINT		;768 Grafik-Bytes folgen
	LD	a,'L'
	CALL	PRINT
	XOR	A
	CALL	PRINT
	LD	A,'3'
	CALL	PRINT
	LD	A,C		;X-Koordinate innerhalb einer
	OUT	(XLSB),A	;Bildschirmhälfte
	LD	E,0FFH		;Abwärtszähler für Y-Koordinate
B90	LD	A,E		;nächstes Byte lesen
	OUT	(YLSB),A	;Y-Wert vorgeben
TEST1	LD	A,0FH		;Ausgabe anfordern
	OUT	(CMD),A
	CALL	WAIT
	IN	A,(MFREE)	;HRG-Byte
	LD	D,A		;zweimal lesen
	LD	A,0FH		;um eventuelle
	OUT	(CMD),A		;Lesefehler
	CALL	WAIT		;zu erkennen
	IN	A,(MFREE)
	CP	D
	JR	NZ,TEST1	;wenn keine Übereinstimmung
	CPL			;Byte invertiert drucken
	CALL	PRINT		;dreimal drucken, um
	CALL	PRINT		;Bildschirmformat
	CALL	PRINT		;ungfähr zu treffen
	DEC	E		;nächster Y-Wert
	LD	A,0FFH		;waren das schon alle?
	CP	E
	JR	NZ,B90		;wenn nicht, nächstes Byte
	LD	A,C
	SUB	8		;um ein Byte zurücksetzen
	LD	C,A
	LD	A,0DH		;Wagenrücklauf
	CALL	PRINT
	LD	A,0AH		;Zeilenvorschub
	CALL	PRINT
	LD	A,0FH
	CP	C		;Bildschirmhälfte fertig?
	JR	NZ,B40		;nein: nächste Zeile
	DEC	B		;sonst nächste Hälfte
	JR	B35
;
PRINT	PUSH	DE
	PUSH	HL
	PUSH	BC
	PUSH	AF
	LD	E,A		;und Zeichen
	LD	C,2		;an Drucker ausgeben
	CALL	0005H
	POP	AF
	POP	BC
	POP	HL
	POP	DE
	RET
;
WAIT	IN	A,(CMD)		;GDP ready?
	AND	04H
	JR	Z,WAIT
	RET
	END